home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 157_01 / tr.c < prev   
Text File  |  1987-10-10  |  11KB  |  389 lines

  1. /* 
  2. HEADER:     CUG
  3. TITLE:        TR.C - Translate Characters
  4. VERSION:    1.00
  5. DATE:        05/03/85
  6. DESCRIPTION:    "A full implementation of the UNIX 'tr' utility.
  7.         It copies input from 'stdin' to 'stdout' with
  8.         substitution or deletion of selected characters
  9.         that are specified in the command line that
  10.         invokes the program."
  11. KEYWORDS:    tr, filter, UNIX, translate
  12. SYSTEM:        Any
  13. FILENAME:    TR.C
  14. WARNINGS:    "Any operating system that converts all command
  15.         line lowercase characters to uppercase makes this
  16.         utility more of a curiosity than a useful tool.
  17.         Lowercase characters can only be specified by
  18.         their octal equivalents."
  19. CRC:        xxxx
  20. SEE-ALSO:    None
  21. AUTHORS:    Ian Ashdown - byHeart Software
  22. COMPILERS:    Any C compiler
  23. REFERENCES:    AUTHORS: Bell Telephone Laboratories;
  24.         TITLE:     UNIX Programmer's Manual Vol. 1, p. 166;
  25. ENDREF
  26. */
  27.  
  28. /*-------------------------------------------------------------*/
  29.  
  30. /* TR.C  - Translate Characters 
  31.  *
  32.  * Version 1.00        May 5th, 1985
  33.  *
  34.  * Copyright 1985:    Ian Ashdown
  35.  *            byHeart Software
  36.  *            1089 West 21st Street
  37.  *            North Vancouver, B.C. V7P 2C2
  38.  *            Canada
  39.  *
  40.  * This program may be copied for personal, non-commercial use
  41.  * only, provided that the above copyright notice is included in
  42.  * all copies of the source code. Copying for any other use
  43.  * without previously obtaining the written permission of the
  44.  * author is prohibited.
  45.  *
  46.  * pHILANTHROPICAL nOTES:
  47.  *
  48.  * Considerable time and effort went into the development of this
  49.  * software, which was expressly written for the public domain.
  50.  * The author will gladly accept any and all monetary
  51.  * contributions for the purpose of continuing such work!
  52.  *
  53.  * USAGE: tr [-cds] [string_1 [string_2] ]
  54.  *
  55.  * Notes:
  56.  *
  57.  * This is a full implementation of the UNIX "tr" utility. It
  58.  * copies input from "stdin" to "stdout" with substitution or
  59.  * deletion of selected characters. Input characters of
  60.  * "string_1" are mapped into the corresponding characters of
  61.  * "string_2". When "string_2" is shorter than "string_1", the
  62.  * last character of "string_2" is repeatedly mapped into the
  63.  * remaining characters of "string_1".
  64.  *
  65.  * Any combination of the options "-cds" may be used. These
  66.  * options are: 
  67.  *
  68.  *    -c    COMPLEMENT option. All input characters except
  69.  *        those of "string_1" are translated to the first
  70.  *        character of "string_2". Any remaining characters
  71.  *        of "string_2" are ignored.
  72.  *
  73.  *    -d    DELETE option. All input characters matching
  74.  *        those in "string_1" are deleted from the output
  75.  *        to "stdout". "String_2" is not used. 
  76.  *
  77.  *    -s    SQUEEZE option. All sequences of repeated
  78.  *        characters in the input from "stdin" that match
  79.  *        characters in "string_1" are each converted to a
  80.  *        single character (their "string_2" translations).
  81.  *
  82.  * In either string, the notation "x-y" means the range of
  83.  * characters from 'x' to 'y' in increasing ASCII order. 
  84.  *
  85.  * The following "\x"-style escape sequences are supported: 
  86.  *
  87.  *     \n    newline            (non-UNIX)
  88.  *    \t    horizontal tab        (non-UNIX)
  89.  *    \b    backspace        (non-UNIX)
  90.  *    \r    carriage return        (non-UNIX)
  91.  *    \f    form feed        (non-UNIX)
  92.  *    \ddd    ddd (where 'ddd' is one to three
  93.  *        octal digits)
  94.  *    \c    c (where 'c' is anything else)
  95.  *
  96.  * BUGS:
  97.  *
  98.  * The ASCII NUL character is always deleted from the output - it
  99.  * cannot be specified in either string.
  100.  *
  101.  * Some operating system command processors will not pass
  102.  * lowercase characters and certain other reserved characters to
  103.  * a program in command-line arguments (e.g. - CP/M). All that
  104.  * can be done is to either specify these characters by their
  105.  * octal equivalents (e.g. - 'a' is \141, 'z' is \172), or modify
  106.  * this program such that it specifically asks for the two
  107.  * strings after the program has been invoked (which makes the
  108.  * utility incompatible with the UNIX version of "tr").
  109.  */
  110.  
  111. /*** Definitions ***/
  112.  
  113. #define TRUE     1
  114. #define FALSE     0
  115.  
  116. #define OPT_ERR  0    /* Error codes */
  117. #define CMD_ERR  1
  118. #define BSL_ERR  2
  119. #define DSH_ERR  3
  120.  
  121. /*** Typedefs ***/
  122.  
  123. typedef int BOOL;    /* Boolean flag */
  124.  
  125. /*** Include Files ***/
  126.  
  127. #include <stdio.h>
  128. #include <ctype.h>
  129.  
  130. /*** Main Body Of Program ***/
  131.  
  132. main(argc,argv)
  133. int argc;
  134. char **argv;
  135. {
  136.   static char translate[128];    /* Character translation array */
  137.   char ch_1,        /* String_1 character */
  138.        ch_2,        /* String_2 character */
  139.        low_1 = NULL,    /* String_1 low range character */
  140.        high_1,        /* String_1 high range character */
  141.        low_2 = NULL,    /* String_2 low range character */
  142.        high_2,        /* String_2 low range character */
  143.        *str_1,        /* String_1 pointer */
  144.        *str_2,        /* String_2 pointer */
  145.        *opt_ptr,    /* Command line option pointer */
  146.        exp_str();
  147.   int i,        /* Temporary variable */
  148.       trans,        /* Translation character */
  149.       curr,        /* Current input character */
  150.       prev = NULL;    /* Previous input character */
  151.   BOOL cflag = FALSE,    /* Complement option flag */
  152.        dflag = FALSE,    /* Delete option flag */
  153.        sflag = FALSE,    /* Squeeze option flag */
  154.        r_1 = FALSE,    /* String_1 range flag */
  155.        r_2 = FALSE;    /* String_2 range flag */
  156.   void error();
  157.  
  158.   /* Parse the command line for user-selected options */
  159.  
  160.   while(--argc && (*++argv)[0] == '-')
  161.     for(opt_ptr = argv[0]+1; *opt_ptr != '\0'; opt_ptr++)
  162.       switch(toupper(*opt_ptr))
  163.       {
  164.     case 'C':    /* Complement flag */
  165.       cflag = TRUE;
  166.       break;
  167.     case 'D':    /* Delete flag */
  168.       dflag = TRUE;
  169.       break;
  170.     case 'S':    /* Squeeze flag */
  171.       sflag = TRUE;
  172.       break;
  173.     default:    /* Illegal command line option */
  174.       error(OPT_ERR,NULL);
  175.        }
  176.  
  177.   /* Check for valid command line */
  178.  
  179.   if(!((dflag == TRUE && argc) || (argc > 1)))
  180.     error(CMD_ERR);
  181.  
  182.   /* Expand the source and translation strings */
  183.  
  184.   str_1 = argv;
  185.   str_2 = ++argv;
  186.  
  187.   if(cflag == FALSE)    /* Complement option not selected */
  188.   {
  189.     while(ch_1 = exp_str(str_1,&low_1,&high_1,&r_1))
  190.     {
  191.       if(curr = exp_str(str_2,&low_2,&high_2,&r_2))
  192.     ch_2 = curr;
  193.       translate[ch_1] = ch_2;
  194.     }
  195.     for(i = 1; i < 128; i++)
  196.       if(translate[i] == NULL)
  197.     translate[i] = i;
  198.   }
  199.   else    /* Complement option selected */
  200.   {
  201.     while(ch_1 = exp_str(str_1,&low_1,&high_1,&r_1))
  202.       translate[ch_1] = ch_1;
  203.     ch_2 = exp_str(str_2,&low_2,&high_2,&r_2);
  204.     for(i = 1; i < 128; i++)
  205.       if(translate[i] == NULL)
  206.     translate[i] = ch_2;
  207.   }
  208.  
  209.   /* Process the input */
  210.  
  211.   while((curr = getchar()) != EOF)
  212.   {
  213.     trans = translate[curr];
  214.     if(dflag == FALSE)        /* Delete option not selected */
  215.     {
  216.       if(sflag == FALSE)    /* Squeeze option not selected */
  217.     putchar(trans);
  218.       else            /* Squeeze option selected */
  219.       {
  220.     if(curr == trans)
  221.       putchar(trans);
  222.     else
  223.       if(trans != prev)
  224.         putchar(trans);
  225.     prev = trans;
  226.       }
  227.     }
  228.     else            /* Delete option selected */
  229.       if(curr == trans)
  230.     putchar(trans);
  231.   }
  232. }
  233.  
  234. /*** Functions ***/
  235.  
  236. /* EXP_STR() - Expand a character string. The arguments passed
  237.  *           are a pointer to a pointer to a character string
  238.  *           ("str"), a pointer to the low value of a character
  239.  *           range ("low"), a pointer to the high value of the
  240.  *           same range ("high"), and a pointer to a boolean
  241.  *           flag ("range") that indicated whether or not the
  242.  *           range is currently being expanded. The current
  243.  *           character of "str" or of a range implicit in "str"
  244.  *           currently being expanded is returned. "exp_str"
  245.  *           uses pointer to variables external to the function
  246.  *           rather than internal static variables so that the
  247.  *           calling function can use more than one set of
  248.  *           variables at a time. 
  249.  */
  250.  
  251. char exp_str(str,low,high,range)
  252. char **str,
  253.      *low,
  254.      *high;
  255. BOOL *range;
  256. {
  257.   char curr;
  258.  
  259.   if(*range == FALSE)    /* Not expanding character range */
  260.   {
  261.     switch(curr = *(*str)++)
  262.     {
  263.       case NULL:    /* End of string - back up pointer */
  264.     (*str)--;
  265.     return NULL;
  266.       case '\\':    /* Must be '\x'-style escape sequence */
  267.     curr = literal_sw(str);
  268.     break;
  269.       case '-':        /* Must be c